home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#27 (Dec 87)
/
c daisy printer driver
/
XPrint.c
< prev
Wrap
C/C++ Source or Header
|
1987-10-24
|
10KB
|
418 lines
/*
* XPrint.c. C code for a printer driver for daisy-wheel printers
* for the Macintosh.
* Earle R. Horton. August 17, 1987
* LightspeedC source.
* Set the project type to Device Driver, ID #2.
* Run RMaker to put the resources in the printer resource file.
* Install with Chooser.
*/
#include <WindowMgr.h> /* includes QuickDraw.h, MacTypes.h */
#include <EventMgr.h>
#include <DialogMgr.h>
#include <SerialDvr.h>
#include <FontMgr.h>
#include <HFS.h>
#include <asm.h>
#define DRIVER_MODULE
#include "prglobals.h"
/*
* LightspeedC doesn't provide these as InLines. To save space, I provide
* my own routines. This way, I get around having to link in MacTraps.
*/
int HNoPurge();
int HPurge();
int HLock();
int CloseDriver();
int checkabort();
/* Useful constants */
#define OPEN 0
#define PRIME 1
#define CONTROL 2
#define STATUS 3
#define CLOSE 4
#define SERRESET 8
#define SERSHAKE 10
#define XONCR ((char)17)
#define XOFFCR ((char)19)
#define RESFILEID (-8192)
#define PACKID (-4080)
main(p, d, n)
PrParam *p; /* ==> parameter block */
DCtlPtr d; /* ==> device control entry */
int n; /* entry point selector */
{
/* Check to make sure our data area was allocated. It may not have been
* if we were opened with a low-level open or even a device manager PBOpen()
* and our printer resource file was not opened. Note that we cannot use
* any of LightspeedC's "global" variables until after we get our storage
* from the resource file and lock it down, making A4 point to it. This
* probably does the same thing that the prolog code attempts to do with
* the original 'DATA' resource created by LightspeedC.
*/
int i;
Handle storage;
if(d->dCtlStorage == nil && n != CLOSE){
if (openprinterfile(d) == -1){
PrintErr = ResError();
CloseDriver(d->dCtlRefNum);
return(-1);
}
}
HLock(d->dCtlStorage);
storage = d->dCtlStorage;
asm{
movea.l storage,a0 ;; LightspeedC uses A4 as the base
movea.l (a0),a4 ;; for driver globals.
}
if (d->dCtlStorage != nil) switch (n){ /* dispatch */
case OPEN: /* open */
openprinterfile(d);
if((settings = (Pfg)(GetResource('Stng',RESFILEID))) == nil ||
GetResource('STR#',PACKID) == nil){
CloseDriver(d->dCtlRefNum);
return(-1); /* Can't run without these. */
}
LoadResource(settings);
HNoPurge(settings);
SetControlStrings();
SPopen();
HPurge(settings);
settings = nil;
prpb.ioNamePtr = prname;
break;
case PRIME: /* For read/write calls, not applicable here. */
break;
case CONTROL: /* control */
switch (p->csCode){ /* Device Control Call */
/* p->csCode gives opcode, and we switch on */
/* it to perform low-level Printing calls */
case iPrBitsCtl: /* Send a bitmap to the printer (NA). */
break;
case iPrIOCtl: /* Text streaming. */
iopb.ioParam.ioBuffer = (Ptr)p->lParam1;
iopb.ioParam.ioReqCount = p->lParam2;
asm{
lea iopb,a0
PBWrite
}
break;
case iPrEvtCtl: /* Screen printing. (cmd-shift 4, NA.)*/
break;
case iPrDevCtl: /* CR, LF, FF, etc. */
devicecontrol(p->lParam1);
break;
case iFMgrCtl:
/* Font manager font table modify request. p->lParam1 is a pointer to
* an FMInput record. (IM says we get an FMOutPtr here, but MacsBug says
* we get a pointer to an FMInput. I go with MacsBug.) In addition, the
* integer following p->lParam1 contains our driver reference number and
* a private byte we can use internally.
* The application first does something to determine the characteristics of
* fonts in our printing GrafPort. The Font Manager calls our status
* routine with csParam = 8 and we give it a "font characterization table".
* The Font Manager selects a font, and calls our control routine to confirm
* the choice. We change it to Monaco 9, horizontal scaling. If you need to
* support proportional fonts, then you have to do something about it here
* and in the printing code, too. Good luck.
*/
{
FMInput *fontset;
fontset = (FMInput *)p->lParam1;
fontset->family = monaco;
fontset->face = 0;
fontset->needBits = 0;
fontset->numer = noscale;
fontset->denom = noscale;
if(fontset->device == IDEV10){
fontset->size = 10;
fontset->numer.h = 7;
fontset->denom.h = 6;
}
else if(fontset->device == IDEV15){
fontset->size = 7;
fontset->numer.h = 5;
fontset->denom.h = 6;
}
else fontset->size = 9;
}
break;
default:
break;
}
break;
case STATUS:
switch (p->csCode){ /* Device Status Call */
/* p->csCode gives opcode, and we switch on */
/* it to perform low-level Printing calls */
case iFMgrCtl:
/* Font manager font table request. Help out the Font Manager.
/* p->lParam1 is a pointer to an area in memory in which to put a copy
* of the information describing our font capabilities. p->lParam2 has
* an integer in its high order word which contains the "resolution" to use,
* set in a style dialog with the user. We say we have different horizontal
* resolutions, based on the number of characters per inch used. I believe
* this gets called whenever the application does a GetFontInfo() or
* StringWidth() or whatever for the first time in one of our printing
* GrafPorts. Possibly also when the application tries to change the
* font style.
*/
*((fontab *)p->lParam1) = myfonts;
break;
default:
break;
}
break;
case CLOSE: /* close */
if(storage != nil){
HPurge(storage);
d->dCtlStorage = nil;
}
break;
}
/* done */
return(0);
}
SPopen() /* Open the serial driver and configure it. */
/* Use low-level ROM routines. */
{
ParmBlkPtr pb;
int serconfig;
pb = &iopb;
switch (pport){ /* get the correct port */
case 0: /* modem port */
if(!phone) {
prinit("\p.AOut");
phone = TRUE;
}
drivernum = AoutRefNum;
break;
case 1: /* printer port */
if(!printer) {
prinit("\p.BOut");
printer = TRUE;
}
drivernum = BoutRefNum;
break;
}
/* set up the io parameter block for writing to the serial driver. */
/* a control call resets the baud rate */
pb->ioParam.ioRefNum = drivernum;
pb->ioParam.ioCompletion = nil;
((cntrlParam *)pb)->csCode = SERRESET;
serconfig = data8 + noParity + stop20;
serconfig += mybauds[pbaud].rate;
((cntrlParam*)pb)->csParam[0] = serconfig;
asm{
move.l pb,a0
PBControl
}
#define shake ((SerShk*)&((cntrlParam*)pb)->csParam[0])
shake->errs = FALSE;
shake->evts = FALSE;
shake->fDTR = FALSE;
shake->fInX = FALSE;
if(XonXoff && (theWorld.machineType >= envMachUnknown)){
shake->fXOn = TRUE;
shake->fCTS = FALSE;
shake->xOn = XONCR;
shake->xOff = XOFFCR;
}
else {
shake->fXOn = FALSE;
shake->fCTS = TRUE;
}
((cntrlParam *)pb)->csCode = SERSHAKE;
asm{
move.l pb,a0
PBControl
}
#undef shake
pb->ioParam.ioPosMode = 0;
pb->ioParam.ioPosOffset = 0;
}
prinit(name) /* Open a driver by name. */
StringPtr name; /* ROM serial driver? RAM serial driver? Who cares? */
{
iopb.ioParam.ioNamePtr = name;
iopb.ioParam.ioCompletion = nil;
iopb.ioParam.ioPermssn = 0;
asm{
lea iopb,a0
PBOpen
}
}
/*
* Set the printer control strings based on what is in our STR# resource.
*/
SetControlStrings()
{
unsigned char *strptr;
unsigned char **mystrings;
mystrings = (unsigned char **)GetResource('STR#',PACKID);
if(mystrings != nil){
LoadResource(mystrings);
copystr( (strptr = (*mystrings)+2) , prlfstr);
copystr( (strptr += (*strptr) + 1) , prinitstr);
copystr( (strptr += (*strptr) + 1) , prtopstr);
copystr( (strptr += (*strptr) + 1) , preopstr);
copystr( (strptr += (*strptr) + 1) , preofstr);
decode(prlfstr);
decode(prinitstr);
decode(prtopstr);
decode(preopstr);
decode(preofstr);
}
}
decode(str)
unsigned char *str;
{
register unsigned char i,count;
count = 1;
for(i=0;str[0]-i++;){
if (str[i] == '^') str[count] = 31 & str[++i];
else str[count] = str[i];
count++;
}
str[0] = count - 1;
}
/*
* This is for copying PASCAL strings. Simple.
*/
copystr(src,dst)
unsigned char *src,*dst;
{
asm{
clr.l d0
move.l src,a0
move.l dst,a1
move.b (a0),d0
loop:
move.b (a0)+,(a1)+
dbra d0,@loop
}
}
devicecontrol(code) /* Handle printer device control calls. */
long code;
{
switch(code){
case lPrReset:
printstring(prinitstr);
break;
case lPrPageEnd:
printstring(preopstr);
break;
case lPrLineFeed:
case lPrLFSixth:
case lPrLFEighth:
printstring(prlfstr);
break;
default: /* Unknown parameter. */
break;
}
}
printstring(string) /* Send a printer control string to the */
/* serial driver. */
unsigned char *string;
{
iopb.ioParam.ioBuffer = (Ptr)(string+1);
iopb.ioParam.ioReqCount = (long)(string[0]);
asm{
lea iopb,a0
PBWrite
}
}
/* Find the system folder, and open our printer resource file, if we can.
* Fill in a global SysEnvRec, which might be useful for other stuff.
*/
int openprinterfile(d)
DCtlPtr d;
{
SysEnvRec myWorld;
StringHandle ourname;
int therefnum;
Handle storage;
if(d->dCtlStorage != nil)
HPurge(d->dCtlStorage);
ourname = (StringHandle)GetResource('STR ',0xE000);
LoadResource(ourname);
HNoPurge(ourname); /* Get printer resource file name. */
HLock(ourname);
SysEnvirons(1,&myWorld);
if(myWorld.machineType >= envMachUnknown)
therefnum = OpenRFPerm(*ourname,myWorld.sysVRefNum,fsCurPerm);
else
therefnum = OpenResFile(*ourname);
HPurge(ourname);
if (therefnum != -1){
d->dCtlStorage = (Handle)GetResource('PREC',RESFILEID);
if(d->dCtlStorage != nil){
LoadResource(d->dCtlStorage);
DetachResource(d->dCtlStorage);
HNoPurge(d->dCtlStorage);
HLock(d->dCtlStorage);
storage = d->dCtlStorage;
asm{
movea.l storage,a0 ;; LightspeedC uses A4
movea.l (a0),a4 ;; for driver globals.
}
theWorld = myWorld;
}
}
return (therefnum);
}
int HNoPurge(c)
char *c;
{
asm{
move.l c,a0
HNoPurge
}
}
int HPurge(c)
char *c;
{
asm{
move.l c,a0
HPurge
}
}
int HLock(c)
char *c;
{
asm{
move.l c,a0
HLock
}
}
int CloseDriver(refnum)
int refnum;
{
ParamBlockRec closepb;
asm{
lea closepb,a0
move.w refnum,24(a0)
clr.l 12(a0)
PBClose
move.w 16(a0),d0
}
}